package com.yzc.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yzc.constants.MqConstants;
import com.yzc.execption.ZcException;
import com.yzc.mapper.TicketMainOrderMapper;
import com.yzc.model.entity.ticket_order.OrderMain;
import com.yzc.rabbit.OrderStatus;
import com.yzc.redis.RedisUtil;
import com.yzc.result.Result;
import com.yzc.result.ResultCodeEnum;
import com.yzc.service.PaymentService;
import com.yzc.util.AuthContextHolder;
import com.yzc.util.RabbitMQUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static com.yzc.constant.RedisConstant.CACHE_EXPIRE_TIME;
import static com.yzc.constant.RedisConstant.ORDER_RECORD_MAIN;

@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {

    private final TicketMainOrderMapper orderMainMapper;
    private final RabbitMQUtil rabbitMQUtil;
    private final RedisUtil redisUtil;
    private final logPaymentServiceImpl logPaymentService;
    private final RedisTemplate<String, String> redisTemplate;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> payOrder(Long orderId, String paymentMethod) {
        boolean paymentSuccess = false; // 支付结果
        OrderMain order = null; // 订单对象
        try {
            // 参数校验
            validateOrder(orderId, paymentMethod);

            // 从缓存或数据库中获取订单
            order = getOrderFromCacheOrDb(orderId);

            // 检查订单状态
            if (OrderStatus.status_UNPAID.getCode() != order.getOrderStatus()) {
                log.error("订单状态已更新，无需支付，订单状态: {}", order.getOrderStatus());
                return Result.fail(ResultCodeEnum.FAIL.getCode(), "订单当前状态不可支付");
            }

            // 异步支付
            CompletableFuture<Boolean> paymentFuture = mockPaymentGatewayAsync(paymentMethod, order.getTotalAmount());
            try {
                paymentSuccess = paymentFuture.get(10, TimeUnit.SECONDS); // 设置超时时间
            } catch (Exception e) {
                log.error("支付超时或失败，订单ID: {}", orderId, e);
                return Result.fail(ResultCodeEnum.FAIL.getCode(), "支付超时");
            }
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            // 处理支付结果
            if (paymentSuccess) {
                updateOrderStatus(orderId, OrderStatus.status_PAID.getCode());
                // 记录支付成功日志

                logPaymentService.logPaymentResult(orderId, order, OrderStatus.status_PAID.getCode(), "支付结果，支付方式: " + paymentMethod,request);
                rabbitMQUtil.cancelDelayedMessage(MqConstants.DELAY_EXCHANGE_NAME, "order.unpaid", orderId);
                return Result.success();
            } else {
                // 记录支付失败日志
                logPaymentService.logPaymentResult(orderId, order, OrderStatus.status_UNPAID.getCode(), "支付结果，支付方式: " + paymentMethod,request);
                return Result.fail(ResultCodeEnum.FAIL.getCode(), "支付失败，支付方式: " + paymentMethod + "，失败原因: 网络超时");
            }


        } catch (ZcException e) {
            log.error("支付过程中发生异常，订单ID: {}", orderId, e);
            return Result.fail(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("支付过程中发生未知异常，订单ID: {}", orderId, e);
            return Result.fail(ResultCodeEnum.FAIL.getCode(), "支付过程中发生未知异常");
        } finally {
            // 清理 AuthContextHolder
            AuthContextHolder.clear();
        }
    }

    /**
     * 参数校验
     */
    private void validateOrder(Long orderId, String paymentMethod) {
        if (orderId == null || orderId <= 0) {
            throw new ZcException(ResultCodeEnum.FAIL.getCode(), "订单ID无效");
        }
        if (paymentMethod == null || paymentMethod.isEmpty()) {
            throw new ZcException(ResultCodeEnum.FAIL.getCode(), "支付方式不能为空");
        }
    }

    /**
     * 从缓存或数据库中获取订单
     */
    private OrderMain getOrderFromCacheOrDb(Long orderId) {
        String cacheKey = ORDER_RECORD_MAIN + orderId;
        OrderMain order = (OrderMain) redisUtil.get(cacheKey);
        if (order == null) {
            order = orderMainMapper.selectOne(new LambdaQueryWrapper<OrderMain>().eq(OrderMain::getOrderId, orderId));
            if (order == null) {
                throw new ZcException(ResultCodeEnum.FAIL.getCode(), "订单不存在");
            }
            redisUtil.set(cacheKey, order, CACHE_EXPIRE_TIME);
        }
        return order;
    }


    /**
     * 更新订单状态
     */
    public void updateOrderStatus(Long orderId, int status) {
        UpdateWrapper<OrderMain> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .eq("order_id", orderId)
                .set("order_status", status)
                .set("payment_time", new Date());

        int rows = orderMainMapper.update(updateWrapper);
        if (rows <= 0) {
            throw new ZcException(ResultCodeEnum.FAIL.getCode(), "订单状态更新失败");
        }
        // 更新缓存
        String cacheKey = ORDER_RECORD_MAIN + orderId;
        OrderMain order = orderMainMapper.selectOne(new LambdaQueryWrapper<OrderMain>().eq(OrderMain::getOrderId, orderId));
        redisUtil.set(cacheKey, order, CACHE_EXPIRE_TIME);
    }

    /**
     * 模拟支付接口（异步）
     */
    @Async
    public CompletableFuture<Boolean> mockPaymentGatewayAsync(String paymentMethod, BigDecimal amount) {
        return CompletableFuture.completedFuture(mockPaymentGateway(paymentMethod, amount));
    }

    /**
     * 模拟支付接口
     */
    private boolean mockPaymentGateway(String paymentMethod, BigDecimal amount) {
        return Math.random() < 0.9; // 模拟 90% 的成功率
    }

}